import 'dart:async';

import 'package:rxdart/rxdart.dart';

import '../../common/test_page.dart';
import '../utils.dart';

class MapTestPage extends TestPage {
  MapTestPage(super.title) {
    test('Rx.mapNotNull', () {
      expect(
          Stream.fromIterable(['1', '2', 'invalid_num', '3', 'invalid_num', '4'])
              .mapNotNull(int.tryParse));

      // 0-----1-----2-----3-----...-----8-----9-----|
      // 1-----null--3-----null--...-----9-----null--|
      // 1--3--5--7--9--|
      final stream = Stream.periodic(const Duration(milliseconds: 10), (i) => i)
          .take(10)
          .transform(MapNotNullStreamTransformer((i) => i.isOdd ? null : i + 1));
      expect(stream);
    });

    test('Rx.mapNotNull.shouldThrowA', () {
      expect(
        Stream<bool>.error(Exception()).mapNotNull((_) => true),
      );

      expect(
        Rx.concat<int>([
          Stream.fromIterable([1, 2]),
          Stream.error(Exception()),
          Stream.value(3),
        ]).mapNotNull((i) => i.isEven ? i + 1 : null),
      );
    });

    test('Rx.mapNotNull.shouldThrowB', () {
      expect(
        Stream.fromIterable([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).mapNotNull((i) {
          if (i == 4) throw Exception();
          return i.isEven ? i + 1 : null;
        }),
      );
    });

    test('Rx.mapNotNull.asBroadcastStream', () {
      final stream = Stream.fromIterable([2, 3, 4, 5, 6])
          .mapNotNull<int>((i) => null)
          .asBroadcastStream();

      stream.listen(null);
      stream.listen(null);

      expect(true);
    });

    test('Rx.mapNotNull.singleSubscription', () {
      final stream = StreamController<int>().stream.mapNotNull((i) => i);

      expect(stream.isBroadcast);
      stream.listen(null);
      expect(() => stream.listen(null));
    });

    test('Rx.mapNotNull.pause.resume', () async {
      final subscription =
      Stream.fromIterable([2, 3, 4, 5, 6]).mapNotNull((i) => i).listen(null);

      subscription
        ..pause()
        ..onData(((data) {
          expect(data);
          subscription.cancel();
        }))
        ..resume();
    });

    test('Rx.mapNotNull.nullable', () {
      nullableTest<String?>(
            (s) => s.mapNotNull((i) => i),
      );
    });

    test('Rx.mapTo', () async {
      expect(Rx.range(1, 4).mapTo(true));
    });

    test('Rx.mapTo.shouldThrow', () async {
      expect(
          Rx.range(1, 4).concatWith([Stream<int>.error(Error())]).mapTo(true),
      );
    });

    test('Rx.mapTo.reusable', () async {
      final transformer = MapToStreamTransformer<int, bool>(true);
      final stream = Rx.range(1, 4).asBroadcastStream();

      stream.transform(transformer).listen(null);
      stream.transform(transformer).listen(null);

      expect(true);
    });

    test('Rx.mapTo.pause.resume', () async {
      late StreamSubscription<bool> subscription;
      final stream = Stream.value(1).mapTo(true);

      subscription = stream.listen(((value) {
        expect(value);

        subscription.cancel();
      }));

      subscription.pause();
      subscription.resume();
    });

    test('Rx.mapTo accidental broadcast', () async {
      final controller = StreamController<int>();

      final stream = controller.stream.mapTo(1);

      stream.listen(null);
      expect(() => stream.listen(null));

      controller.add(1);
    });

    test('Rx.mapTo.nullable', () {
      nullableTest<String?>(
            (s) => s.mapTo('String'),
      );
    });

  }

}